﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using System.Management;
using CDOEXM;


namespace ExchangeSGAnalysis
{
    class ExchangeAnalysis
    {
        private static Decimal maxDatabaseSize = 80;

        private static String WMIPATH = "\\root\\cimv2";
        //private System.Collections.ArrayList alStorageGroup;
        
        public struct Database
        {
            public string name;
            public Decimal size;
            public decimal whiteSpaceSize;
            public bool warning;    
        }

        public struct StorageGroup
        {
            public string name;
            public Database database;
        }

        public ExchangeAnalysis(string serverName)
        {
            LUNFreeSpace(serverName);
            ExchangeStorageGroups(serverName);
        }
        private bool Analysis(StorageGroup sg)
        {
            Decimal mbdbSize = 0;

            mbdbSize = sg.database.size - sg.database.whiteSpaceSize;

            if (mbdbSize > maxDatabaseSize)
            {
                return true;
            }
            else
            {
                Decimal percentageFree = (1 - (mbdbSize / maxDatabaseSize)) * 100;
                if (percentageFree < 5)
                {
                    return true;
                }
            }
            return false;
           
        }

        public int checkStatus()
        {


            //return 0 when finished
            return 0;
        }

        private void ExchangeStorageGroups(string servername)
        {
            CDOEXM.IExchangeServer exchsvr      = new CDOEXM.ExchangeServerClass();
            CDOEXM.IStorageGroup sg             = new CDOEXM.StorageGroupClass();
            CDOEXM.MailboxStoreDB mbsdb         = new CDOEXM.MailboxStoreDBClass();

            System.Collections.Hashtable ht = EventLog1221(servername, 30);
           
            try
            {
                
                exchsvr.DataSource.Open(servername, null,
                    ADODB.ConnectModeEnum.adModeReadWrite,
                    ADODB.RecordCreateOptionsEnum.adOpenIfExists,
                    ADODB.RecordOpenOptionsEnum.adOpenSource,
                    null,
                    null);
            }
            catch (Exception e)
            {
                Console.Error.WriteLine(e.ToString());
                Environment.Exit(1);
            }

            foreach (string sgname in (System.Collections.IEnumerable)exchsvr.StorageGroups)
            {
                try
                {
                    sg.DataSource.Open(sgname, null,
                    ADODB.ConnectModeEnum.adModeReadWrite,
                    ADODB.RecordCreateOptionsEnum.adOpenIfExists,
                    ADODB.RecordOpenOptionsEnum.adOpenSource,
                    null,
                    null);
                }
                catch (Exception e)
                {
                    Console.Error.WriteLine(e.ToString());
                    Environment.Exit(1);
                }
                foreach (string mbname in (System.Collections.IEnumerable)sg.MailboxStoreDBs)
                {
                    try
                    {
                        mbsdb.DataSource.Open(mbname, null,
                            ADODB.ConnectModeEnum.adModeReadWrite,
                            ADODB.RecordCreateOptionsEnum.adOpenIfExists,
                            ADODB.RecordOpenOptionsEnum.adOpenSource,
                            null,
                            null);
                    }
                    catch (Exception e)
                    {
                        Console.Error.WriteLine(e.ToString());
                        Environment.Exit(1);
                    }
                    Decimal edbFileSize = FileSize(mbsdb.DBPath, servername);
                    Decimal stmFileSize = FileSize(mbsdb.SLVPath, servername);
                    String mailBoxName = ParseMailboxStoreDBName(mbname);

                    if (ht.ContainsKey(mailBoxName))
                    {
                        StorageGroup storageGroup = (StorageGroup)ht[mailBoxName];
                        storageGroup.database.size = edbFileSize + stmFileSize;
                        storageGroup.database.warning = Analysis(storageGroup);

                        Console.WriteLine("SG Name: {0}, DB Name: {1}, DB Size: {2}, Whitespace: {3}, Warning: {4}",
                            storageGroup.name,
                            storageGroup.database.name,
                            storageGroup.database.size,
                            storageGroup.database.whiteSpaceSize,
                            storageGroup.database.warning);

                    }
                }
            }

            //Console.ReadLine();
        }
        private String ParseMailboxStoreDBName(String mailBoxName)
        {
            String[] mailBoxNameArray = mailBoxName.Split( new char[] { '=', ',' } );
            return mailBoxNameArray[1];
        }

        private String ParseStorageGroupName(String storageGroupName)
        {
            String[] storageGroupNameArray = storageGroupName.Split(new char[] { '=', ',' });
            return storageGroupNameArray[1];
        }
        private StorageGroup ParseEventLog(String eventMsg)
        {
            String[] messageArrayMailbox = eventMsg.Split('"');
            String[] messageArraySize = messageArrayMailbox[2].Split(' ');
            String SGMB = messageArrayMailbox[1];

            String storageGroup = SGMB.Split('\\')[0];
            String mailBoxDB = SGMB.Split('\\')[1];
            Decimal freeSpace = Convert.ToUInt32(messageArraySize[2]) / (Decimal)1024;

            StorageGroup sg = new StorageGroup();
            sg.database = new Database();

            sg.name = storageGroup;
            sg.database.name = mailBoxDB;
            sg.database.whiteSpaceSize = freeSpace;

            return sg;
        }
        private Decimal FileSize(String path, String servername)
        {
            UInt64 fileSize = 0;
            System.Management.ManagementScope mangeScope = null;
            StringBuilder sb = new StringBuilder();
            System.Management.ConnectionOptions connOpt = new System.Management.ConnectionOptions();

            try
            {
                mangeScope = new System.Management.ManagementScope("\\\\" + servername + WMIPATH);
                mangeScope.Connect();
            }
            catch (Exception e)
            {
                Console.Error.WriteLine(e.ToString());
                Environment.Exit(1);
            }

            path = path.Replace("\\", "\\\\");

            sb.AppendFormat("SELECT * FROM CIM_DataFile WHERE Name = \"{0}\"", path);

            System.Management.SelectQuery sq = new SelectQuery(sb.ToString());

            try
            {
                ManagementObjectCollection mocDataFile = new ManagementObjectSearcher(mangeScope, sq).Get();
                foreach (ManagementObject moDataFile in mocDataFile)
                {
                    if (moDataFile["FileSize"] != null)
                    {
                        fileSize = (UInt64)moDataFile["FileSize"];
                    }

                    fileSize >>= 20;
                }
            }
            catch (Exception e)
            {
                Console.Error.WriteLine(e.ToString());
                Environment.Exit(1);
            }
            return (Decimal)fileSize / (Decimal)1024;
        }
        private System.Collections.Hashtable EventLog1221(string serverName, int numMB)
        {
            System.Collections.Hashtable htWhiteSpace = new System.Collections.Hashtable();
            StorageGroup sg;
            String message = "";
            String timeWritten = "";
            int count = 0;
            System.Management.ManagementScope mangeScope = null;

            System.Management.ConnectionOptions connOpt = new System.Management.ConnectionOptions();
            System.Management.SelectQuery sq = new SelectQuery("SELECT * FROM Win32_NTLogEvent WHERE EventCode = 1221");

            try
            {
                mangeScope = new System.Management.ManagementScope("\\\\" + serverName + WMIPATH);
                mangeScope.Connect();
                ManagementObjectCollection moc = new ManagementObjectSearcher(mangeScope, sq).Get();
                
                foreach (ManagementObject mo in moc)
                {
                    if (count > numMB)
                        break;
                    if (mo["Message"] != null)
                    {
                        message = (String)mo["Message"];
                    }
                    if (mo["TimeWritten"] != null)
                    {
                        timeWritten = (String)mo["TimeWritten"];
                    }
                    
                    sg = ParseEventLog(message);

                    if (!htWhiteSpace.ContainsKey(sg.database.name))
                        htWhiteSpace.Add(sg.database.name, sg);

                    //Console.WriteLine("{0},{1},{2}", timeWritten, sg.database.name, sg.database.size);
                    count++;
                }
            }
            catch (Exception e)
            {
                Console.Error.WriteLine(e.ToString());
                Environment.Exit(1);
            }
            return htWhiteSpace;
        }

        private void LUNFreeSpace(string servername)
        {
            UInt64 lunFreeSize = 0;
            String deviceID = "";
            System.Management.ManagementScope mangeScope = null;

            System.Management.ConnectionOptions connOpt = new System.Management.ConnectionOptions();
            System.Management.SelectQuery sq = new SelectQuery("SELECT * FROM Win32_LogicalDisk WHERE DriveType = 3");
            try
            {
                mangeScope = new System.Management.ManagementScope("\\\\" + servername + WMIPATH);
                mangeScope.Connect();
                ManagementObjectCollection mocLogicalDisk = new ManagementObjectSearcher(mangeScope, sq).Get();

                foreach (ManagementObject mo in mocLogicalDisk)
                {
                    if (mo["FreeSpace"] != null)
                    {
                        lunFreeSize = (UInt64)mo["FreeSpace"];
                    }
                    if (mo["DeviceID"] != null)
                    {
                        deviceID = (String)mo["DeviceID"];
                    }
                    lunFreeSize >>= 20;

                    Decimal dLunFreeSize = (Decimal)lunFreeSize / (Decimal)1024;

                    Console.WriteLine("{0},{1}", deviceID, dLunFreeSize);

                }
            }
            catch (Exception e)
            {
                Console.Error.WriteLine(e.ToString());
                Environment.Exit(1);
            }
        }

    }
}
